import { CustomRequestOptions } from '@/interceptors/request'
import { useUserStore } from '@/store'

type CustomRequestOptionsOmit = Omit<CustomRequestOptions, 'url' | 'method'>

export default class ApiClient {
  private static http<T>(options: Omit<CustomRequestOptions, 'isBaseUrl'>) {
    let requestTask
    const promise = new Promise<ResData<T>>((resolve, reject) => {
      requestTask = uni.request({
        ...options,
        success: (res: any) => {
          /* -------- 请求成功 ----------- */
          if ((res.statusCode >= 200 && res.statusCode < 300) || res.data.code === 0) {
            return resolve(res.data as ResData<T>)
          }

          /* -------- token 失效，跳转到登录页 ----------- */
          if (res.data.code == 401 || res.statusCode == 401) {
            const store = useUserStore()
            // 清除 用户信息（包括 token）
            store.clearUserInfo()
            // 跳转到登录页
            uni.navigateTo({ url: '/pages/login/login' })
            uni.showToast({
              title: '登录已过期，请重新登录',
              icon: 'none'
            })
            return reject(res)
          }

          /* -------- 剩余情况都默认请求异常 ----------- */
          uni.showToast({
            title: res.data.msg || res.data.message || '请求异常',
            icon: 'none'
          })
          reject(res)
        },
        fail: err => {
          if (err.errMsg === 'request:fail abort') {
            console.log(`请求 ${options.url} 被取消`)
          } else {
            reject(err)
          }
        }
      })
    })
    return {
      ...promise, // 补全 Promise 的类型
      then: promise.then.bind(promise),
      catch: promise.catch.bind(promise),
      finally: promise.finally.bind(promise),
      [Symbol.iterator]: promise[Symbol.iterator],
      abort: () => {
        // 取消请求
        requestTask.abort()
      }
    }
  }
  // GET
  public static get<T>(url: string, options?: CustomRequestOptionsOmit): Promise<ResData<T>> {
    return this.http<T>({
      url,
      method: 'GET',
      ...options
    })
  }
  // POST
  public static post<T>(url: string, options?: CustomRequestOptionsOmit): Promise<ResData<T>> {
    return this.http<T>({
      url,
      method: 'POST',
      ...options
    })
  }
  // PUT
  public static put<T>(url: string, options?: CustomRequestOptionsOmit): Promise<ResData<T>> {
    return this.http<T>({
      url,
      method: 'PUT',
      ...options
    })
  }
  // DELETE
  public static delete<T>(url: string, options?: CustomRequestOptionsOmit): Promise<ResData<T>> {
    return this.http<T>({
      url,
      method: 'DELETE',
      ...options
    })
  }
}
